package com.ml.loan.common.utils;

import com.ml.loan.common.exception.BusinessException;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;

public class SmsRSAUtil {

    /**
     * <p>
     * 单次加密最大密文长度，这里仅仅指2048bit 长度密钥
     * </p>
     */
    public static final int MAX_ENCRYPT_BLOCK = 245;
    /**
     * 加密算法
     */
    public static final String ALGORITHM_RSA = "RSA";
    /**
     * 算法/模式/填充
     */
    public static final String CIPHER_TRANSFORMATION_RSA = "RSA/ECB/PKCS1Padding";

    /**
     * 得到公钥
     *
     * @param key     密钥字符串（经过base64编码）
     * @param charset
     * @throws Exception
     */
    public static PublicKey getPublicKey(String key, String charset) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(key.getBytes(charset));
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance(ALGORITHM_RSA);
        PublicKey publicKey = keyFactory.generatePublic(keySpec);
        return publicKey;
    }

    /**
     * 公钥加密
     *
     * @param content   待加密内容
     * @param publicKey 公钥
     * @param charset   字符集，如UTF-8, GBK, GB2312
     * @return 密文内容
     * @throws Exception
     */
    public static String rsaEncrypt(String content, String publicKey, String charset) {
        try {
            PublicKey pubKey = getPublicKey(publicKey, charset);
            Cipher cipher = Cipher.getInstance(CIPHER_TRANSFORMATION_RSA);
            cipher.init(Cipher.ENCRYPT_MODE, pubKey);
            byte[] data = StringUtils.isEmpty(charset) ? content.getBytes()
                    : content.getBytes(charset);
            int inputLen = data.length;
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            int offSet = 0;
            byte[] cache;
            int i = 0;
            // 对数据分段加密
            while (inputLen - offSet > 0) {
                if (inputLen - offSet > MAX_ENCRYPT_BLOCK) {
                    cache = cipher.doFinal(data, offSet, MAX_ENCRYPT_BLOCK);
                } else {
                    cache = cipher.doFinal(data, offSet, inputLen - offSet);
                }
                out.write(cache, 0, cache.length);
                i++;
                offSet = i * MAX_ENCRYPT_BLOCK;
            }
            byte[] encryptedData = Base64.encodeBase64(out.toByteArray());
            out.close();

            return StringUtils.isEmpty(charset) ? new String(encryptedData)
                    : new String(encryptedData, charset);
        } catch (Exception e) {
            throw new BusinessException("error occured in rsaEncrypt: EncryptContent = " + content + ",charset = " + charset);
        }
    }

}
